﻿//
// Created by Grishul Eugeny
//
// See license in License.txt
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Diagnostics;
using NCommander.Core;

namespace NCommander.NodeProviders
{
	/// <summary>
	/// External provider for Windows filesystems.
	/// </summary>
	[ShortName( "file" )]
	internal sealed class FileSystemProvider : NodeProvider
	{
		private class FileSystemNode : Node
		{
			public FileSystemInfo Info;
			public FileSystemNode ParentNode;

			public override string Path
			{
				get { return Info.FullName; }
			}

			public override Node Parent { get { return ParentNode; } }

			public override NodeType Type
			{
				get
				{
					if( Info is DirectoryInfo )
						return NodeType.Internal;

					if( Info is FileInfo )
						return NodeType.External;

					return NodeType.Invalid;
				}
			}
		}

		private class FileSystemFollowUpNode : FollowUpNode
		{
			public FileSystemNode Node;
			public override Node Parent { get { return Node.Parent; } }
		}

		private FileSystemNode _currentNode;

		public FileSystemProvider()
		{
			var windowsSystemDrive = DriveInfo.GetDrives().First( x => Environment.GetFolderPath( Environment.SpecialFolder.System ).StartsWith( x.Name ) );

			_currentNode = new FileSystemNode() { Info = windowsSystemDrive.RootDirectory };
		}

		#region NodeProvider Members

		public override Node[] Roots
		{
			get
			{
				return DriveInfo.GetDrives().Select( x => new FileSystemNode() { Info = x.RootDirectory } ).ToArray();
			}
		}

		public override Node CurrentNode
		{
			get { return _currentNode; }
			set
			{
				var upnode = value as FileSystemFollowUpNode;

				if( upnode != null )
					_currentNode = upnode.Node;
				else
					_currentNode = ( FileSystemNode ) value;

				InvokeRefresh();
			}
		}

		public override Node GetNode( string path )
		{
			if( Directory.Exists( path ) )
				return new FileSystemNode() { Info = new DirectoryInfo( path ), ParentNode = ( FileSystemNode ) GetNode( Path.GetDirectoryName( path ) ) };

			if( File.Exists( path ) )
				return new FileSystemNode() { Info = new FileInfo( path ), ParentNode = ( FileSystemNode ) GetNode( Path.GetDirectoryName( path ) ) };

			return null;
		}

		public override IEnumerable<Node> GetNodes()
		{
			var currentDirectoryNode = ( DirectoryInfo ) _currentNode.Info;

			if( DriveInfo.GetDrives().All( x => x.RootDirectory.Name != currentDirectoryNode.Name ) )
				yield return new FileSystemFollowUpNode() { Node = ( FileSystemNode ) _currentNode.Parent };

			foreach( var directory in currentDirectoryNode.GetDirectories() )
				yield return new FileSystemNode() { Info = directory, ParentNode = _currentNode };

			foreach( var file in currentDirectoryNode.GetFiles() )
				yield return new FileSystemNode() { Info = file, ParentNode = _currentNode };
		}

		public override void OnExecute( Node node )
		{
			if( node.Type == NodeType.Internal )
				CurrentNode = node;
			else if( node.Type == NodeType.External )
				Process.Start( node.Path );
		}

		public override void OnEdit( Node[] nodes )
		{
			var notepadPlusPlus = string.Join( Path.DirectorySeparatorChar.ToString(), new[] { Environment.GetFolderPath( Environment.SpecialFolder.ProgramFiles ), "notepad++", "notepad++.exe" } );

			if( File.Exists( notepadPlusPlus ) )
				Process.Start( notepadPlusPlus, string.Join( " ", nodes.Select( x => "\"" + x.Path + "\"" ).ToArray() ) );
		}

		public override void OnOptions( Node node )
		{
		}

		#endregion

		public override string ToString()
		{
			return _currentNode.Info.Name;
		}
	}
}
